home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / util / moni / idle_led.lha / idle_led.c next >
Encoding:
C/C++ Source or Header  |  1994-03-02  |  5.4 KB  |  238 lines

  1.  
  2. /*
  3.  
  4. Program:    Idle Led
  5. Version:    2.1a    1/3/94
  6. Author:        Lindsay Meek (meek@fizzy.csu.murdoch.edu.au)
  7.  
  8. Description:    Whenever the CPU is busy, the power led goes on else it is off.
  9.  
  10.         This is the second version that operates by attaching itself
  11.         to the vertical blanking interrupt. A low priority (-127)
  12.         task is active which increments a counter and turns off the
  13.         light. When this task does not run, the vblank irq detects
  14.         the non-incrementing counter and turns the light on.
  15.  
  16.         This version is more system friendly than 1.0
  17.  
  18.         The CPU must be busy for more than 1 vbi for the
  19.         light to activate
  20. */
  21.  
  22. #include <exec/nodes.h>
  23. #include <exec/tasks.h>
  24. #include <exec/interrupts.h>
  25. #include <hardware/cia.h>
  26. #include <hardware/custom.h>
  27. #include <hardware/intbits.h>
  28. #include <libraries/dos.h>
  29.  
  30. /* Assembly stub */
  31. extern void IdleIrq(void);
  32. extern void LightState(UWORD state);
  33.  
  34. /* A string print (no formatting) that doesn't use as much memory as printf */
  35. void zprint(char *string)
  36. {
  37.     extern BPTR Output(void);
  38.     extern long Write(BPTR file, char *buffer, long length);
  39.  
  40.     Write(Output(),string,strlen(string));
  41.  
  42.     exit(1);
  43. }
  44.  
  45. static UWORD idlelight_flag;    /* Flag saying to turn the light on or off */
  46.  
  47. /* Make the light 'active' depending on the idle flag */
  48. void LightActive(void)
  49. {
  50.     LightState(idlelight_flag);
  51. }
  52.  
  53. /* Make the light 'inactive' depending on the idle flag */
  54. void LightInactive(void)
  55. {
  56.     LightState(!idlelight_flag);
  57. }
  58.  
  59. /* System structure names */
  60. #define UTILITY_NAME "Idle_LED"
  61.  
  62. /* various counters used to detect the idle state in the vblank */
  63. static ULONG idle_vbi_cnt_limit[3];
  64.  
  65. /* Run this as a process. It aborts when it detects a CTRL_C signal */
  66. main(int argc,char **argv)
  67. {
  68.     extern struct Task *FindTask(char *);
  69.     struct Task *met;
  70.     struct Interrupt mei;
  71.     UWORD threshold;
  72.     WORD oldpri;
  73.     char *oldname;
  74.     int i,kill_flag;
  75.  
  76.     threshold=50;        /* Default: CPU threshold: > 50 % */
  77.     idlelight_flag=1;    /* Default: Make light come on for a busy cpu */
  78.     kill_flag=0;        /* Don't kill it */
  79.  
  80.     for(i=1;i<argc;i++)
  81.     {
  82.         if(!stricmp(argv[i],"off")) kill_flag=1;    /* disable */
  83.         else
  84.         if(!stricmp(argv[i],"dim")) idlelight_flag=0;    /* dim = busy */
  85.         else
  86.         if(!stricmp(argv[i],"threshold"))
  87.         {
  88.             if(++i > argc) 
  89.                 zprint("Missing argument");
  90.  
  91.             threshold=atoi(argv[i]);
  92.  
  93.             /* clip threshold to stop silly buggers */
  94.             if(threshold < 1) threshold=1;
  95.             if(threshold > 99) threshold=99;
  96.         }
  97.         else
  98.         if(stricmp(argv[i],"on") && stricmp(argv[i],"bright"))
  99.         {    
  100.             zprint("Usage: Idle_LED {ON} {OFF} {BRIGHT} {DIM} {THRESHOLD n}\n");
  101.         }
  102.     }
  103.  
  104.     met=FindTask(UTILITY_NAME);
  105.  
  106.     if(kill_flag)
  107.     {
  108.         if(met==NULL)
  109.             zprint("Idle_LED not running!\n");
  110.  
  111.         /* Send CTRL-C signal to task */
  112.         Signal(met,SIGBREAKF_CTRL_C);
  113.  
  114.         zprint("Idle_LED terminating\n");
  115.     }
  116.  
  117.     if(met!=NULL)
  118.         zprint("Idle_LED already running!\n");
  119.  
  120.     mei.is_Node.ln_Type = NT_INTERRUPT;
  121.     mei.is_Node.ln_Pri  = -127;
  122.     mei.is_Node.ln_Name = UTILITY_NAME;
  123.     mei.is_Data = (APTR)idle_vbi_cnt_limit;
  124.     mei.is_Code = IdleIrq;
  125.  
  126.     /* reset counter,last state */
  127.  
  128.     AddIntServer(INTB_VERTB, &mei);        /* Install IRQ server */
  129.  
  130.     met=FindTask(NULL);        /* Fetch this tcb */
  131.     oldpri=met->tc_Node.ln_Pri;    /* Save old priority */
  132.     oldname=met->tc_Node.ln_Name;    /* Save old name */
  133.     met->tc_Node.ln_Name=UTILITY_NAME;    /* Redirect task name */
  134.     met->tc_Node.ln_Pri=40;        /* Raise priority for calibration */
  135.  
  136.     idle_vbi_cnt_limit[0]=0;
  137.     idle_vbi_cnt_limit[1]=0;
  138.     idle_vbi_cnt_limit[2]=0;
  139.  
  140.     /* wait for next vbi */
  141.     while(idle_vbi_cnt_limit[0]==0) ;
  142.  
  143.     /* count # of increments in one frame (for calibration) */
  144.     idle_vbi_cnt_limit[2]=0;
  145.     idle_vbi_cnt_limit[0]=0;
  146.     while(idle_vbi_cnt_limit[0] == 0) 
  147.         idle_vbi_cnt_limit[2]++;
  148.  
  149.     /* > threshold % load is busy */
  150.     idle_vbi_cnt_limit[2] = (idle_vbi_cnt_limit[2] * threshold)/100;
  151.  
  152.     met->tc_Node.ln_Pri=-127;    /* Make priority VERY low for idle */
  153.  
  154.     /* Busy loop for eating idle cpu cycles */
  155.     while((met->tc_SigRecvd & SIGBREAKF_CTRL_C)==0)    /* Abort on CTRL_C */
  156.     {
  157.         /* Increment idle counter */
  158.         idle_vbi_cnt_limit[1]++;
  159.     }
  160.  
  161.     RemIntServer(INTB_VERTB,&mei);            /* Remove IRQ server */
  162.  
  163.     met->tc_Node.ln_Pri=oldpri;            /* Change priority back */
  164.     met->tc_Node.ln_Name=oldname;            /* Change name back */
  165.  
  166.     /* Turn on power led */
  167.     LightState(1);
  168.  
  169.     return 0;
  170. }
  171.  
  172. #asm
  173.  
  174. ;
  175. ;Assembly section for vertical blanking interrupt server
  176. ;
  177. ;You may have to put this into a seperate .asm file and compile to get it working
  178. ;with your C compiler
  179. ;
  180.  
  181.     include    "hardware/cia.i"
  182.  
  183. _ciaa    =    $bfe001        ;i defined it here so i could use the small model!
  184.  
  185.     public    _IdleIrq
  186.     public    _LightActive
  187.     public    _LightInactive
  188.     public    _LightState
  189.     
  190.     public    _geta4
  191.  
  192. _IdleIrq:
  193.  
  194.     move.l    a4,-(sp)    ;save a4
  195.     jsr    _geta4        ;retrieve a4 for global variables
  196.  
  197.     addq.l    #1,(a1)+
  198.  
  199.     move.l    (a1),d0        ;idle_cnt
  200.     clr.l    (a1)+        ;=0
  201.     cmp.l    (a1),d0        ;>=idle_limit
  202.     bge.s    _IdleIrq1    ;yes - then its idle
  203.  
  204.     jsr    _LightActive    ;turn on light - cpu is busy
  205.  
  206.     move.l    (sp)+,a4
  207.  
  208.     moveq    #0,d0        ;permit other servers to execute
  209.     rts            
  210.  
  211. _IdleIrq1:
  212.  
  213.     jsr    _LightInactive    ;turn off light - cpu is idle
  214.     
  215.     move.l    (sp)+,a4
  216.  
  217.     moveq    #0,d0        ;permit other servers to execute
  218.     rts
  219.  
  220. ;
  221. ;void LightState(UWORD state)
  222. ;
  223. ;
  224. ;The routine is coded in assembly to prevent the C compiler from
  225. ;splitting up the read-modify-write cycle (bad news for hardware)
  226. ;
  227. _LightState:
  228.  
  229.     tst.w    4(sp)            ;check state
  230.     beq.s    ls1            ;off?
  231.     bclr.b    #CIAB_LED,_ciaa+ciapra    ;turn on power light (cpu is busy)
  232.     rts
  233.  
  234. ls1:    bset.b    #CIAB_LED,_ciaa+ciapra    ;turn off power light (cpu is idle)
  235.     rts
  236.  
  237. #endasm
  238.